enum DirectionType {
  left, right, up, down, stop
}
export class Snack {
  private width = 600
  private height = 600
  private canvas = document.createElement("canvas")
  private ctx: CanvasRenderingContext2D | null = null
  scope = 0
  private step = 15
  constructor(ele: HTMLDivElement, _width: number = 600, _height: number = 600) {
    this.width = _width
    this.height = _height
    this.canvas.width = this.width
    this.canvas.height = this.height
    if (!ele.querySelector("canvas")) {
      ele.appendChild(this.canvas)
    }
  }

  start() {
    this.isEnd = false
    this.scope = 0
    if (this.lisFun) {
      this.lisFun(this.scope)
    }
    this.snakeStruct = {
      body: [
        { x: Math.floor(this.width / 2), y: Math.floor(this.height / 2) },
      ],
      size: 1,
      direction: { x: DirectionType.stop, y: DirectionType.up }
    }
    document.addEventListener("keydown", (ev) => {
      this.lisKey(ev)
    })
    this.init()
  }

  private lisKey(ev: KeyboardEvent) {
    if (ev.code == "ArrowDown") {
      if (this.snakeStruct.direction.y == DirectionType.up) {
        return
      }
      this.snakeStruct.direction.y = DirectionType.down
      this.snakeStruct.direction.x = DirectionType.stop
    } else if (ev.code == "ArrowUp") {
      if (this.snakeStruct.direction.y == DirectionType.down) {
        return
      }
      this.snakeStruct.direction.y = DirectionType.up
      this.snakeStruct.direction.x = DirectionType.stop

    } else if (ev.code == "ArrowLeft") {
      if (this.snakeStruct.direction.x == DirectionType.right) {
        return
      }
      this.snakeStruct.direction.x = DirectionType.left
      this.snakeStruct.direction.y = DirectionType.stop

    } else if (ev.code == "ArrowRight") {
      if (this.snakeStruct.direction.x == DirectionType.left) {
        return
      }
      this.snakeStruct.direction.x = DirectionType.right
      this.snakeStruct.direction.y = DirectionType.stop

    }
  }

  private snakeStruct = {
    body: [
      { x: Math.floor(this.width / 2), y: Math.floor(this.height / 2) }
    ],
    size: 1,
    direction: { x: DirectionType.left, y: DirectionType.up }
  }

  private init() {
    this.ctx = this.canvas.getContext("2d")
    if (this.ctx) {
      this.reRender()
      this.render()
    }
  }

  private renderTime: number | undefined
  isEnd = false
  private render() {
    // init
    this.drawSnack()
    this.renderTime = setInterval(() => {
      if (this.isEnd) {
        clearInterval(this.renderTime)
        console.log("结束游戏");
        this.updateEndGame()
      } else {
        this.updateGame()
      }

    }, 100)
  }

  private master: any[] = []
  private updateMaster() {

    if (this.master.length == 0) {
      let x = Math.ceil(Math.random() * this.width - 15)
      let y = Math.ceil(Math.random() * this.height - 15)
      this.master.push({
        x: x, y: y
      })
    }

    this.master.filter(item => {
      let { x, y } = item
      if (this.ctx) {
        this.ctx.fillStyle = 'rgb(251, 189, 204)'
        this.ctx.fillRect(x, y, this.step, this.step)
      }
    })
  }

  private updateGame() {
    if (this.ctx) {
      this.updateSnack()
      this.reRender()
      this.updateMaster()
      this.drawSnack()

    }
  }

  private reRender() {
    if (this.ctx) {
      this.ctx.fillStyle = 'rgb(0,0,0)'
      this.ctx.fillRect(0, 0, this.width, this.height)
    }
  }

  private drawSnack() {
    if (this.ctx) {
      this.ctx.fillStyle = 'rgb(0,255,0)'
      this.snakeStruct.body.filter(item => {
        this.ctx?.fillRect(
          item.x, item.y,
          this.step, this.step)
      })
    }
    if (this.judgeBox()) {
      this.master.length = 0
      this.snakeStruct.body.push({
        x: this.snakeStruct.body[this.snakeStruct.body.length - 1].x + this.step,
        y: this.snakeStruct.body[this.snakeStruct.body.length - 1].y + this.step,
      })
      this.scope += 1
      if (this.lisFun) {
        this.lisFun(this.scope)
      }

    }

  }
  // 判断是否相撞
  private judgeBox() {
    if (this.master.length == 0) {
      return false
    }

    let x1 = this.master[0].x
    let x2 = this.master[0].x + this.step
    let y1 = this.master[0].y
    let y2 = this.master[0].y + this.step


    let x3 = this.snakeStruct.body[0].x
    let x4 = this.snakeStruct.body[0].x + this.step
    let y3 = this.snakeStruct.body[0].y
    let y4 = this.snakeStruct.body[0].y + this.step

    if (Math.max(x1, x3) <= Math.min(x2, x4) && Math.max(y1, y3) <= Math.min(y2, y4)) {
      return true
    }
    return false
  }

  private updateSnack() {
    // let item = this.snakeStruct.body[0]
    let _lastitem = { x: this.snakeStruct.body[0].x, y: this.snakeStruct.body[0].y }
    this.snakeStruct.body.filter((item, index) => {
      let _item = { x: item.x, y: item.y }
      if (index == 0) {
        if (this.snakeStruct.direction.x == DirectionType.left) {
          item.x -= this.step
          this.snakeStruct.direction.y = DirectionType.stop
        } else if (this.snakeStruct.direction.x == DirectionType.right) {
          item.x += this.step
          this.snakeStruct.direction.y = DirectionType.stop
        } else if (this.snakeStruct.direction.y == DirectionType.up) {
          item.y -= this.step
          this.snakeStruct.direction.x = DirectionType.stop
        } else if (this.snakeStruct.direction.y == DirectionType.down) {
          item.y += this.step
          this.snakeStruct.direction.x = DirectionType.stop
        }
      } else {
        item.x = _lastitem.x
        item.y = _lastitem.y
        _lastitem = _item
      }

    })
    if (this.snakeStruct.body[0].x < 0 || this.snakeStruct.body[0].x > this.width || this.snakeStruct.body[0].y < 0
      || this.snakeStruct.body[0].y > this.height
    ) {
      this.isEnd = true
    }



  }


  private updateEndGame() {
    if (this.ctx) {
      // background
      this.ctx.fillStyle = 'rgb(0,0,0)'
      this.ctx.fillRect(0, 0, this.width, this.height)
      this.ctx.fillStyle = 'rgb(255,255,255)'
      this.ctx.fillText("GAME  OVER", this.width / 2 - 50, this.height / 2)
    }
    document.removeEventListener("keydown", this.lisKey)
  }

  private lisFun: Function | undefined
  addListen(fun: Function) {
    this.lisFun = fun
  }



  dispose() {
    this.isEnd = true
    document.removeEventListener("keydown", this.lisKey)
    this.lisFun = undefined
  }
}


